package top.lshaci.framework.file.oss.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import com.aliyun.oss.OSS;
import com.aliyun.oss.model.DeleteObjectsRequest;
import com.aliyun.oss.model.DeleteObjectsResult;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.OSSObject;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.unit.DataSize;
import top.lshaci.framework.file.enums.FileErrorInfo;
import top.lshaci.framework.file.exception.FileDownloadException;
import top.lshaci.framework.file.exception.FileOperateException;
import top.lshaci.framework.file.exception.FileUploadException;
import top.lshaci.framework.file.oss.enums.FileOssErrorInfo;
import top.lshaci.framework.file.oss.exception.FileOssException;
import top.lshaci.framework.file.oss.service.OssFileOperateService;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.function.Supplier;

/**
 * OssFileOperateServiceImpl
 *
 * @author lshaci
 * @since 1.0.9
 */
@Slf4j
@AllArgsConstructor
public class OssFileOperateServiceImpl implements OssFileOperateService {

    private final OSS oss;

    private final String defaultBucket;

    private final DataSize maxSize;

    @Override
    public String single(InputStream inputStream, String bucket, Supplier<String> pathSupplier) throws IOException {
        verifyBucket(bucket);
        final int available = inputStream.available();
        if (available <= 0) {
            throw new FileUploadException(FileErrorInfo.size_is_empty);
        }
        log.debug("Upload size: {}, Max size: {}", available, maxSize);
        if (available > maxSize.toBytes()) {
            throw new FileUploadException(FileErrorInfo.exceed_limit);
        }
        final String key = pathSupplier.get();
        verifyKey(key);
        oss.putObject(bucket, key, inputStream);

        log.debug("Upload success, Path is: {}", key);
        return key;
    }

    @Override
    public void delete(String bucket, String path) {
        verifyBucketAndKey(bucket, path);
        oss.deleteObject(bucket, path);
    }

    @Override
    public DeleteObjectsResult delete(DeleteObjectsRequest deleteObjectsRequest) {
        List<String> keys = deleteObjectsRequest.getKeys();
        if (CollUtil.isEmpty(keys)) {
            log.warn("未指定需要删除的文件");
            return null;
        }
        verifyBucket(deleteObjectsRequest.getBucketName());
        return oss.deleteObjects(deleteObjectsRequest);
    }

    @Override
    public void write(GetObjectRequest request, OutputStream outputStream) {
        verifyBucketAndKey(request.getBucketName(), request.getKey());
        boolean exist = oss.doesObjectExist(request);
        if (!exist) {
            log.error(FileErrorInfo.not_exist.getMsg() + "; bucket: {}, path: {}", request.getBucketName(), request.getKey());
            throw new FileDownloadException(FileErrorInfo.not_exist);
        }
        final OSSObject object = oss.getObject(request);
        final InputStream objectContent = object.getObjectContent();
        IoUtil.copy(objectContent, outputStream);
    }

    @Override
    public String bucket() {
        return this.defaultBucket;
    }

    /**
     * 验证 bucket 是否为空
     *
     * @param bucket 存储的 bucket
     */
    private void verifyBucket(String bucket) {
        if (StrUtil.isBlank(bucket)) {
            throw new FileOssException(FileOssErrorInfo.bucket_is_blank);
        }
    }

    /**
     * 验证 key 是否为空
     *
     * @param key 文件的 key
     */
    private void verifyKey(String key) {
        if (StrUtil.isBlank(key)) {
            throw new FileOperateException(FileErrorInfo.path_is_blank);
        }
    }

    /**
     * 验证 bucket 和 key 是否为空
     *
     * @param bucket 存储的 bucket
     * @param key    文件的 key
     */
    private void verifyBucketAndKey(String bucket, String key) {
        verifyKey(key);
        verifyBucket(bucket);
    }
}
